Add gtk_tree_model_iter_previous() vfunc
authorSzilárd Pfeiffer <mailbox@pfeifferszilard.hu>
Thu, 6 Jan 2011 04:39:11 +0000 (23:39 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 6 Jan 2011 04:39:11 +0000 (23:39 -0500)
https://bugzilla.gnome.org/show_bug.cgi?id=128058

docs/reference/gtk/gtk3-sections.txt
gtk/gtk.symbols
gtk/gtkliststore.c
gtk/gtktreemodel.c
gtk/gtktreemodel.h
gtk/gtktreemodelfilter.c
gtk/gtktreemodelsort.c
gtk/gtktreestore.c
gtk/tests/liststore.c
gtk/tests/treestore.c

index 0b8559f643fcfc69b9071d88285c31987fcfba3d..73c7c9ac8f86201ce156f6dc277539c5e8e69938 100644 (file)
@@ -3948,6 +3948,7 @@ gtk_tree_model_get_iter_first
 gtk_tree_model_get_path
 gtk_tree_model_get_value
 gtk_tree_model_iter_next
+gtk_tree_model_iter_previous
 gtk_tree_model_iter_children
 gtk_tree_model_iter_has_child
 gtk_tree_model_iter_n_children
index 001c345ddba33d500766646ee2830a52a2f79d7a..d423df6e87aac9eff4fd77b3bc5f6e8556cf1d8c 100644 (file)
@@ -3135,6 +3135,7 @@ gtk_tree_model_iter_n_children
 gtk_tree_model_iter_next
 gtk_tree_model_iter_nth_child
 gtk_tree_model_iter_parent
+gtk_tree_model_iter_previous
 gtk_tree_model_ref_node
 gtk_tree_model_row_changed
 gtk_tree_model_row_deleted
index fc43eba05c0e073952ecc098e5fab6f764031bff..4d9c1ddb1c833a3e9b0d3eaf422c901c715c8f04 100644 (file)
@@ -75,6 +75,8 @@ static void         gtk_list_store_get_value       (GtkTreeModel      *tree_mode
                                                    GValue            *value);
 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
                                                    GtkTreeIter       *iter);
+static gboolean     gtk_list_store_iter_previous   (GtkTreeModel      *tree_model,
+                                                   GtkTreeIter       *iter);
 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
                                                    GtkTreeIter       *iter,
                                                    GtkTreeIter       *parent);
@@ -187,6 +189,7 @@ gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
   iface->get_path = gtk_list_store_get_path;
   iface->get_value = gtk_list_store_get_value;
   iface->iter_next = gtk_list_store_iter_next;
+  iface->iter_previous = gtk_list_store_iter_previous;
   iface->iter_children = gtk_list_store_iter_children;
   iface->iter_has_child = gtk_list_store_iter_has_child;
   iface->iter_n_children = gtk_list_store_iter_n_children;
@@ -549,6 +552,26 @@ gtk_list_store_iter_next (GtkTreeModel  *tree_model,
   return !retval;
 }
 
+static gboolean
+gtk_list_store_iter_previous (GtkTreeModel *tree_model,
+                              GtkTreeIter  *iter)
+{
+  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
+  GtkListStorePrivate *priv = list_store->priv;
+
+  g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
+
+  if (g_sequence_iter_is_begin (iter->user_data))
+    {
+      iter->stamp = 0;
+      return FALSE;
+    }
+
+  iter->user_data = g_sequence_iter_prev (iter->user_data);
+
+  return TRUE;
+}
+
 static gboolean
 gtk_list_store_iter_children (GtkTreeModel *tree_model,
                              GtkTreeIter  *iter,
index c65287c99ebc94fd289b90c6c061a63dcc351b60..7b6622f4685f558153af2d2dcbceec5c471efc79 100644 (file)
@@ -1180,6 +1180,59 @@ gtk_tree_model_iter_next (GtkTreeModel  *tree_model,
   return (* iface->iter_next) (tree_model, iter);
 }
 
+static gboolean
+gtk_tree_model_iter_previous_default (GtkTreeModel *tree_model,
+                                      GtkTreeIter  *iter)
+{
+  gboolean retval;
+  GtkTreePath *path;
+
+  path = gtk_tree_model_get_path (tree_model, iter);
+  if (path == NULL)
+    return FALSE;
+
+  retval = gtk_tree_path_prev (path) &&
+           gtk_tree_model_get_iter (tree_model, iter, path);
+  if (retval == FALSE)
+    iter->stamp = 0;
+
+  gtk_tree_path_free (path);
+
+  return retval;
+}
+
+/**
+ * gtk_tree_model_iter_previous:
+ * @tree_model: a #GtkTreeModel
+ * @iter: (inout): the #GtkTreeIter
+ *
+ * Sets @iter to point to the previous node at the current level. If there
+ * is no previous @iter, %FALSE is returned and @iter is set to be invalid.
+ *
+ * Return value: %TRUE if @iter has been changed to the previous node
+ *
+ * Since: 3.0
+ */
+gboolean
+gtk_tree_model_iter_previous (GtkTreeModel *tree_model,
+                              GtkTreeIter  *iter)
+{
+  gboolean retval;
+  GtkTreeModelIface *iface;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  iface = GTK_TREE_MODEL_GET_IFACE (tree_model);
+
+  if (iface->iter_previous)
+    retval = (* iface->iter_previous) (tree_model, iter);
+  else
+    retval = gtk_tree_model_iter_previous_default (tree_model, iter);
+
+  return retval;
+}
+
 /**
  * gtk_tree_model_iter_children:
  * @tree_model: A #GtkTreeModel.
index b706a00f97dcb424988cf2f7b165f8126220ebcc..b290f83c1e67b6579b44933e01e90c64fdf398ab 100644 (file)
@@ -97,6 +97,8 @@ struct _GtkTreeModelIface
                                    GValue       *value);
   gboolean     (* iter_next)       (GtkTreeModel *tree_model,
                                    GtkTreeIter  *iter);
+  gboolean     (* iter_previous)   (GtkTreeModel *tree_model,
+                                   GtkTreeIter  *iter);
   gboolean     (* iter_children)   (GtkTreeModel *tree_model,
                                    GtkTreeIter  *iter,
                                    GtkTreeIter  *parent);
@@ -206,6 +208,8 @@ void              gtk_tree_model_get_value       (GtkTreeModel *tree_model,
                                                  GtkTreeIter  *iter,
                                                  gint          column,
                                                  GValue       *value);
+gboolean          gtk_tree_model_iter_previous   (GtkTreeModel *tree_model,
+                                                 GtkTreeIter  *iter);
 gboolean          gtk_tree_model_iter_next       (GtkTreeModel *tree_model,
                                                  GtkTreeIter  *iter);
 gboolean          gtk_tree_model_iter_children   (GtkTreeModel *tree_model,
index d7a155ac9aa869c1cf0dfc5f18bfecd33b6d0ca9..18e0d594d50eddf1578c607c37f3b0a7df5909c9 100644 (file)
@@ -215,6 +215,8 @@ static void         gtk_tree_model_filter_get_value                       (GtkTr
                                                                            GValue                 *value);
 static gboolean     gtk_tree_model_filter_iter_next                       (GtkTreeModel           *model,
                                                                            GtkTreeIter            *iter);
+static gboolean     gtk_tree_model_filter_iter_previous                   (GtkTreeModel           *model,
+                                                                           GtkTreeIter            *iter);
 static gboolean     gtk_tree_model_filter_iter_children                   (GtkTreeModel           *model,
                                                                            GtkTreeIter            *iter,
                                                                            GtkTreeIter            *parent);
@@ -385,6 +387,7 @@ gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface)
   iface->get_path = gtk_tree_model_filter_get_path;
   iface->get_value = gtk_tree_model_filter_get_value;
   iface->iter_next = gtk_tree_model_filter_iter_next;
+  iface->iter_previous = gtk_tree_model_filter_iter_previous;
   iface->iter_children = gtk_tree_model_filter_iter_children;
   iface->iter_has_child = gtk_tree_model_filter_iter_has_child;
   iface->iter_n_children = gtk_tree_model_filter_iter_n_children;
@@ -2514,6 +2517,41 @@ gtk_tree_model_filter_iter_next (GtkTreeModel *model,
   return FALSE;
 }
 
+static gboolean
+gtk_tree_model_filter_iter_previous (GtkTreeModel *model,
+                                     GtkTreeIter  *iter)
+{
+  int i;
+  FilterLevel *level;
+  FilterElt *elt;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), FALSE);
+  g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, FALSE);
+  g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp, FALSE);
+
+  level = iter->user_data;
+  elt = iter->user_data2;
+
+  i = elt - FILTER_ELT (level->array->data);
+
+  while (i > 0)
+    {
+      i--;
+      elt--;
+
+      if (elt->visible)
+        {
+          iter->user_data2 = elt;
+          return TRUE;
+        }
+    }
+
+  /* no previous visible iter */
+  iter->stamp = 0;
+
+  return FALSE;
+}
+
 static gboolean
 gtk_tree_model_filter_iter_children (GtkTreeModel *model,
                                      GtkTreeIter  *iter,
index 5582da781e3d62347fba1d8d43863b12ab07037e..1fc52266ed9f223392193b8ac6e344c40d7fbc06 100644 (file)
@@ -189,6 +189,8 @@ static void         gtk_tree_model_sort_get_value          (GtkTreeModel
                                                             GValue                *value);
 static gboolean     gtk_tree_model_sort_iter_next          (GtkTreeModel          *tree_model,
                                                             GtkTreeIter           *iter);
+static gboolean     gtk_tree_model_sort_iter_previous      (GtkTreeModel          *tree_model,
+                                                            GtkTreeIter           *iter);
 static gboolean     gtk_tree_model_sort_iter_children      (GtkTreeModel          *tree_model,
                                                             GtkTreeIter           *iter,
                                                             GtkTreeIter           *parent);
@@ -325,6 +327,7 @@ gtk_tree_model_sort_tree_model_init (GtkTreeModelIface *iface)
   iface->get_path = gtk_tree_model_sort_get_path;
   iface->get_value = gtk_tree_model_sort_get_value;
   iface->iter_next = gtk_tree_model_sort_iter_next;
+  iface->iter_previous = gtk_tree_model_sort_iter_previous;
   iface->iter_children = gtk_tree_model_sort_iter_children;
   iface->iter_has_child = gtk_tree_model_sort_iter_has_child;
   iface->iter_n_children = gtk_tree_model_sort_iter_n_children;
@@ -1080,6 +1083,31 @@ gtk_tree_model_sort_iter_next (GtkTreeModel *tree_model,
   return TRUE;
 }
 
+static gboolean
+gtk_tree_model_sort_iter_previous (GtkTreeModel *tree_model,
+                                   GtkTreeIter  *iter)
+{
+  GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model;
+  GtkTreeModelSortPrivate *priv = tree_model_sort->priv;
+  SortLevel *level;
+  SortElt *elt;
+
+  g_return_val_if_fail (priv->child_model != NULL, FALSE);
+  g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
+
+  level = iter->user_data;
+  elt = iter->user_data2;
+
+  if (elt == (SortElt *)level->array->data)
+    {
+      iter->stamp = 0;
+      return FALSE;
+    }
+  iter->user_data2 = elt - 1;
+
+  return TRUE;
+}
+
 static gboolean
 gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model,
                                   GtkTreeIter  *iter,
index fd0b3fff64b6525e8cabd9147e7c96c7c97a0a20..d9a76a9e38eace41c8d5c2b738ec4111bc319ca4 100644 (file)
@@ -104,6 +104,8 @@ static void         gtk_tree_store_get_value       (GtkTreeModel      *tree_mode
                                                    GValue            *value);
 static gboolean     gtk_tree_store_iter_next       (GtkTreeModel      *tree_model,
                                                    GtkTreeIter       *iter);
+static gboolean     gtk_tree_store_iter_previous   (GtkTreeModel      *tree_model,
+                                                   GtkTreeIter       *iter);
 static gboolean     gtk_tree_store_iter_children   (GtkTreeModel      *tree_model,
                                                    GtkTreeIter       *iter,
                                                    GtkTreeIter       *parent);
@@ -236,6 +238,7 @@ gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
   iface->get_path = gtk_tree_store_get_path;
   iface->get_value = gtk_tree_store_get_value;
   iface->iter_next = gtk_tree_store_iter_next;
+  iface->iter_previous = gtk_tree_store_iter_previous;
   iface->iter_children = gtk_tree_store_iter_children;
   iface->iter_has_child = gtk_tree_store_iter_has_child;
   iface->iter_n_children = gtk_tree_store_iter_n_children;
@@ -671,16 +674,33 @@ gtk_tree_store_iter_next (GtkTreeModel  *tree_model,
   g_return_val_if_fail (iter->user_data != NULL, FALSE);
   g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->priv->stamp, FALSE);
 
-  if (G_NODE (iter->user_data)->next)
+  if (G_NODE (iter->user_data)->next == NULL)
     {
-      iter->user_data = G_NODE (iter->user_data)->next;
-      return TRUE;
+      iter->stamp = 0;
+      return FALSE;
     }
-  else
+
+  iter->user_data = G_NODE (iter->user_data)->next;
+
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_store_iter_previous (GtkTreeModel *tree_model,
+                              GtkTreeIter  *iter)
+{
+  g_return_val_if_fail (iter->user_data != NULL, FALSE);
+  g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->priv->stamp, FALSE);
+
+  if (G_NODE (iter->user_data)->prev == NULL)
     {
       iter->stamp = 0;
       return FALSE;
     }
+
+  iter->user_data = G_NODE (iter->user_data)->prev;
+
+  return TRUE;
 }
 
 static gboolean
index 6452fc290364bf34526b15690663468b807ef0f7..e710d9bad25bcfaf6440851c092877aadd8bda27 100644 (file)
@@ -168,6 +168,13 @@ list_store_test_insert_high_values (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -205,6 +212,13 @@ list_store_test_append (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -242,6 +256,13 @@ list_store_test_prepend (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -280,6 +301,20 @@ list_store_test_insert_after (void)
 
   g_assert (!gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 2));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 2));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter3, &iter_copy));
+  g_assert (iter_position (store, &iter3, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -313,6 +348,16 @@ list_store_test_insert_after_NULL (void)
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 0));
   g_assert (iters_equal (&iter2, &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -353,6 +398,20 @@ list_store_test_insert_before (void)
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter3, &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 2));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 2));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter3, &iter_copy));
+  g_assert (iter_position (store, &iter3, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -385,6 +444,13 @@ list_store_test_insert_before_NULL (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -853,6 +919,20 @@ list_store_test_move_before_single (void)
 
 /* iter invalidation */
 
+static void
+list_store_test_iter_previous_invalid (ListStore     *fixture,
+                                       gconstpointer  user_data)
+{
+  GtkTreeIter iter;
+
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (fixture->store),
+                                          &iter) == FALSE);
+  g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE);
+  g_assert (iter.stamp == 0);
+}
+
 static void
 list_store_test_iter_next_invalid (ListStore     *fixture,
                                    gconstpointer  user_data)
@@ -1025,6 +1105,9 @@ main (int    argc,
                   list_store_test_move_before_single);
 
   /* iter invalidation */
+  g_test_add ("/list-store/iter-prev-invalid", ListStore, NULL,
+              list_store_setup, list_store_test_iter_previous_invalid,
+              list_store_teardown);
   g_test_add ("/list-store/iter-next-invalid", ListStore, NULL,
               list_store_setup, list_store_test_iter_next_invalid,
               list_store_teardown);
index c9dbcffba8cbefc2b2c5180d5099294f353039f1..663eaaf580ffe5ba60ae6020ae15fd792caf1584 100644 (file)
@@ -171,6 +171,13 @@ tree_store_test_insert_high_values (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -208,6 +215,13 @@ tree_store_test_append (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -245,6 +259,13 @@ tree_store_test_prepend (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -283,6 +304,20 @@ tree_store_test_insert_after (void)
 
   g_assert (!gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 2));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 2));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter3, &iter_copy));
+  g_assert (iter_position (store, &iter3, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -316,6 +351,16 @@ tree_store_test_insert_after_NULL (void)
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 0));
   g_assert (iters_equal (&iter2, &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -356,6 +401,20 @@ tree_store_test_insert_before (void)
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter3, &iter_copy));
 
+  g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 2));
+  g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 2));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter3, &iter_copy));
+  g_assert (iter_position (store, &iter3, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+
   g_object_unref (store);
 }
 
@@ -388,6 +447,13 @@ tree_store_test_insert_before_NULL (void)
 
   g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter_copy, NULL, 1));
   g_assert (iters_equal (&iter2, &iter_copy));
+  g_assert (iter_position (store, &iter2, 1));
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
+  g_assert (iters_equal (&iter, &iter_copy));
+  g_assert (iter_position (store, &iter, 0));
+
+  g_assert (!gtk_tree_model_iter_previous (GTK_TREE_MODEL (store), &iter_copy));
 
   g_object_unref (store);
 }
@@ -856,6 +922,20 @@ tree_store_test_move_before_single (void)
 
 /* iter invalidation */
 
+static void
+tree_store_test_iter_previous_invalid (TreeStore     *fixture,
+                                       gconstpointer  user_data)
+{
+  GtkTreeIter iter;
+
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+
+  g_assert (gtk_tree_model_iter_previous (GTK_TREE_MODEL (fixture->store),
+                                          &iter) == FALSE);
+  g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE);
+  g_assert (iter.stamp == 0);
+}
+
 static void
 tree_store_test_iter_next_invalid (TreeStore     *fixture,
                                    gconstpointer  user_data)
@@ -1028,6 +1108,9 @@ main (int    argc,
                   tree_store_test_move_before_single);
 
   /* iter invalidation */
+  g_test_add ("/tree-store/iter-prev-invalid", TreeStore, NULL,
+              tree_store_setup, tree_store_test_iter_previous_invalid,
+              tree_store_teardown);
   g_test_add ("/tree-store/iter-next-invalid", TreeStore, NULL,
               tree_store_setup, tree_store_test_iter_next_invalid,
               tree_store_teardown);